<template>
  <CesiumBox ref="containerCesium"></CesiumBox>
  <ThreeBox ref="containerThree" class="pointer-events-none"></ThreeBox>
  <BtnTop :msg="'获取位置信息'" @click="getCameraPosition"></BtnTop>
  <div
    v-show="popupShow"
    class="popupShow"
    :style="{ top: popupTop + 'px', left: popupLeft + 'px' }"
  >
    {{ popupMessage }}
  </div>
</template>

<script setup>
import CesiumBox from "../../components/CesiumBox.vue";
import ThreeBox from "../../components/ThreeBox.vue";
import BtnTop from "../../components/BtnTop.vue";
import { ref, onMounted } from "vue";
import * as Cesium from "cesium";
import * as THREE from "three";
import { FBXLoader } from "../../lib/three/loaders/FBXLoader";

const containerCesium = ref(null);
const containerThree = ref(null);
const popupShow = ref(false);
const popupTop = ref(0);
const popupLeft = ref(0);
const popupMessage = ref("");
let cesiumPara = null;
let threeBox = null;
let threePara = null;
let scene = new THREE.Scene();
let rayArray = [];
let handler = null;
let worldPosition = null;
let materialBefore = null;

function animate() {
  requestAnimationFrame(animate);
  render();
}

function render() {
  threePara.renderer.render(scene, threePara.camera);
}

function initCesium() {
  cesiumPara.viewer.scene.preRender.addEventListener(() => {
    // 同步视角
    threePara.camera.fov = Cesium.Math.toDegrees(
      cesiumPara.viewer.camera.frustum.fovy
    );
    // cesium相机位置
    var cvm = cesiumPara.viewer.camera.viewMatrix;
    var civm = cesiumPara.viewer.camera.inverseViewMatrix;
    // 同步Three相机位置设置
    threePara.camera.matrixWorld.set(
      civm[0],
      civm[4],
      civm[8],
      civm[12],
      civm[1],
      civm[5],
      civm[9],
      civm[13],
      civm[2],
      civm[6],
      civm[10],
      civm[14],
      civm[3],
      civm[7],
      civm[11],
      civm[15]
    );
    threePara.camera.matrixWorldInverse.set(
      cvm[0],
      cvm[4],
      cvm[8],
      cvm[12],
      cvm[1],
      cvm[5],
      cvm[9],
      cvm[13],
      cvm[2],
      cvm[6],
      cvm[10],
      cvm[14],
      cvm[3],
      cvm[7],
      cvm[11],
      cvm[15]
    );
    threePara.camera.updateProjectionMatrix();

    if (worldPosition) {
      let coor = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
        cesiumPara.viewer.scene,
        new Cesium.Cartesian3(worldPosition.x, worldPosition.y, worldPosition.z)
      );
      if (coor) {
        popupTop.value = coor.y;
        popupLeft.value = coor.x;
      }
    }
  });

  cesiumPara.viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(
      124.30013390648544,
      44.42945223476908,
      80.57098743266032
    ),
    orientation: {
      heading: 4.5034801619427975,
      pitch: -0.7873277874079969,
      roll: 6.283181717551608,
    },
    duration: 3,
  });

  handler = new Cesium.ScreenSpaceEventHandler(cesiumPara.viewer.scene.canvas);
}

function initThree() {
  //相机
  threePara.camera = new THREE.PerspectiveCamera(
    45,
    threeBox.clientWidth / threeBox.clientHeight,
    1,
    10000000
  );
  threePara.camera.position.set(0, 0, 1000);
  threePara.camera.lookAt(0, 0, 0);
  threePara.camera.matrixAutoUpdate = false;

  //渲染器
  threePara.renderer = new THREE.WebGLRenderer({ alpha: true });
  threePara.renderer.setPixelRatio(window.devicePixelRatio);
  threePara.renderer.setSize(threeBox.clientWidth, threeBox.clientHeight);
  threeBox.appendChild(threePara.renderer.domElement);

  animate();
}

function addObject(pos, name) {
  //环境纹理
  let loaderTexture = new THREE.CubeTextureLoader();
  loaderTexture.setPath("./three/skybox/Park2/");
  let textureEnvMap = loaderTexture.load([
    "posx.jpg",
    "negx.jpg",
    "posy.jpg",
    "negy.jpg",
    "posz.jpg",
    "negz.jpg",
  ]);

  //加载模型
  let loaderFbx = new FBXLoader();
  loaderFbx.load(
    import.meta.env.VITE_APP_TOMCAT + "/cesium/largemodel/" + name + ".fbx",
    (object) => {
      object.traverse((child) => {
        if (child.isMesh) {
          child.castShadow = true;
          child.receiveShadow = true;

          if (child.material instanceof THREE.MeshLambertMaterial) {
            /* let basicMaterial = new THREE.MeshBasicMaterial({
              color: child.material.color,
            });
            basicMaterial.map = child.material.map;
            child.material = basicMaterial; */
            child.material.map.encoding = THREE.LinearEncoding;
          } else {
            child.material.envMap = textureEnvMap;
          }
          /* if (child.name == "围墙") {
            child.material.map.repeat.x = 5;
            child.material.map.repeat.y = 1;
          } */
          rayArray.push(child);
        }
        if (child.isLight) {
          if (child.name == "阳光") {
            child.intensity = 1.0;
            child.color.r = 1.0;
            child.color.g = 1.0;
            child.color.b = 1.0;
          }
        }
      });

      //环境光
      let ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
      object.add(ambientLight);

      object.position.set(pos.x, pos.y, pos.z);
      object.lookAt(0, 0, 0);
      object.rotateX(-Math.PI * 0.5);
      object.rotateY(Math.PI * 0.53);
      object.translateX(-75);
      object.translateZ(54);
      object.scale.set(0.12, 0.12, 0.12);

      scene.add(object);
    }
  );
}

function addEvent() {
  handler.setInputAction((event) => {
    let mouse = new THREE.Vector2();
    mouse.x = (event.position.x / cesiumPara.viewer.scene.canvas.width) * 2 - 1;
    mouse.y =
      -(event.position.y / cesiumPara.viewer.scene.canvas.height) * 2 + 1;

    let raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(mouse, threePara.camera);

    if (materialBefore) {
      if (materialBefore instanceof Array) {
        for (let i = 0; i < materialBefore.length; i++) {
          materialBefore[i].mesh.material = materialBefore[i].material;
        }
      } else {
        materialBefore.mesh.material = materialBefore.material;
      }
      materialBefore = null;
    }

    let intersects = raycaster.intersectObjects(rayArray);
    if (intersects.length > 0) {
      worldPosition = intersects[0].point;
      popupShow.value = true;
      popupMessage.value = intersects[0].object.name;
      if (intersects[0].object.material instanceof Array) {
        for (let i = 0; i < intersects[0].object.material.length; i++) {
          if (intersects[0].object.material[i].color) {
            materialBefore = [];
            materialBefore.push({
              mesh: intersects[0].object,
              material: intersects[0].object.material[i],
            });

            let material = intersects[0].object.material[i].clone();
            material.color.setRGB(0, 1, 1);
            intersects[0].object.material[i] = material;
          }
        }
      } else {
        if (intersects[0].object.material.color) {
          materialBefore = {
            mesh: intersects[0].object,
            material: intersects[0].object.material,
          };

          let material = intersects[0].object.material.clone();
          material.color.setRGB(0, 1, 1);
          intersects[0].object.material = material;
        }
      }

      /* intersects[0].object.visible = false;
      rayArray.splice(rayArray.indexOf(intersects[0].object), 1); */
    } else {
      worldPosition = null;
      popupShow.value = false;
      popupMessage.value = "";
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}

function getCameraPosition() {
  cesiumPara.cameraPosition();
}

onMounted(() => {
  cesiumPara = containerCesium.value.cesiumPara;
  threeBox = containerThree.value.threeBox;
  threePara = containerThree.value.threePara;
  initCesium();
  initThree();
  addObject(Cesium.Cartesian3.fromDegrees(124.2992, 44.43007, 0), "测试");
  addEvent();
});
</script>

<style lang="scss" scoped>
.popupShow {
  position: absolute;
  padding: 5px 10px;
  transform: translate(-100%, -100%);
  background: gray;
  border-radius: 4px;
  z-index: 50;
}
</style>
